#include <math.h>
#include "FrameBufferHandler.h"
#include <gl/glut.h>
#include "ObjHandler.h"
#include <malloc.h>
#include <glui.h>
#include "ShaderHandler.h"
#include "TextureHandler.h"
#include "MatixInvert.h"
#include "floatimage.H"


#pragma comment(lib,"glui32.lib");

#define DEEPBLURSTEP	4
#define SHALLOWBLURSTEP 4

#define SPECLAYER	11
#define DEEPLAYER	12
#define SHALLOWLAYER	13
#define SINGLELAYER	14

int debug=30;

GLUI *glui;
GLUI_Rollout *SingleLayerControl;
GLUI_Rollout *SpecLayerControl;
GLUI_Rollout *DeepLayerControl;
GLUI_Rollout *ShallowLayerControl;

OBJHandler mesh;

int *displayID;

int deepWeightID;
int shallowWeightID;
int maskID;
int deepAlbedoID;
int shallowAlbedoID;
int specRough;


int brdfID;
float displayType=0;

//int diffLayer=0;
//int singleLayer=0;

int windowWidth=1024, windowHeight=768;
int diffuseWidth, diffuseHeight;

float obj_rot[16];
float lig_rot[16];

GLfloat light_position[4]={0.0, 0.0, 35.0, 1.0};

GLfloat eye_position[4]={0,0,35,1};

GLfloat singleParam[4]={0.7,0.5,0,0};

GLfloat light_distance=50;

int specLayer=0;
int deepsLayer=0;
int shallowsLayer=0;
int singlesLayer=0;

int KdC[3]={8,8,8};
int KshineC=8;
float KmC=0.2;
float KfC=2.5;
int KsC=10;
float KrC=0.8;

GLfloat Kd[3]={0.8,0.8,0.8};
GLfloat Ks[3]={0.7,0.7,0.7};
GLfloat Kshine=0.8;
GLfloat Step[2];

CGcontext context;
CGprofile vProfile, fProfile;

GLuint bufferID;

int diffAlbedoID;
int specAlbedoID;
int chanelR;
int chanelB;
int chanelG;
int chanelS;

float gaussianWidth;
int gaussianIrradiance;
int gaussianStretch;

int gaussianDisplay=0;

GLfloat ProjectMatrix[16];
GLfloat MVMatrix[16];
GLfloat LightProjectMatrix[16];
GLfloat LightMVMatrix[16];
GLfloat MInvMatrix[16];
GLfloat MTranMatrix[16];

ShaderHandler vRender,fRender, vShadow, fShadow, vWorld2UV, fWorld2UV, vGaussianU, fGaussianU, vGaussianV, fGaussianV;
ShaderHandler vIrradiance, fIrradiance;

FrameBufferHandler ShadowBuffer, World2UVBuffer, InterBuffer, DeepGaussianBuffer[DEEPBLURSTEP], ShallowGaussianBuffer[SHALLOWBLURSTEP];
FrameBufferHandler IrradianceBuffer;

GLfloat ProjectionLight[16];
GLfloat ProjectionLightOgl[16];

GLfloat ObjectToLight[16];
GLfloat ObjectToLightOgl[16];

GLfloat ProjectiveLight[16];
GLfloat ProjectiveLightOgl[16];

int *texture;
float denorm=1;

float scaleTerm=1.0;
bool initial=true;

void cgErrorCallback(void)
{
	CGerror lastError = cgGetError();
	if(lastError) {
		const char *listing = cgGetLastListing(context);
		printf("%s\n", cgGetErrorString(lastError));
		printf("%s\n", listing);
		exit(-1);
	}
}

void initFrameBuffer()
{
	glewInit();

	GLuint irradianceID;
	GLuint shadowID;

	glGenFramebuffersEXT(1,&shadowID);
	glGenFramebuffersEXT(1,&bufferID);
	glGenFramebuffersEXT(1,&irradianceID);


	ShadowBuffer.SetBufferID(shadowID);
	ShadowBuffer.SetUpFBO(DEP,windowWidth*2,windowHeight*2);
	IrradianceBuffer.SetBufferID(irradianceID);
	IrradianceBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight,5);
	World2UVBuffer.SetBufferID(bufferID);
	World2UVBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	InterBuffer.SetBufferID(bufferID);
	InterBuffer.SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	for (int i=0;i<DEEPBLURSTEP;i++)
	{
		DeepGaussianBuffer[i].SetBufferID(bufferID);
		DeepGaussianBuffer[i].SetUpFBO(TEX,diffuseWidth/denorm,diffuseHeight/denorm);
	}
	for (int i=0;i<SHALLOWBLURSTEP;i++)
	{
		ShallowGaussianBuffer[i].SetBufferID(bufferID);
		ShallowGaussianBuffer[i].SetUpFBO(TEX,diffuseWidth,diffuseHeight);
	}
}

void loadTexture()
{
	texture=new int[8];

	TextureHandler DeepScatteringWeightHandler;
	DeepScatteringWeightHandler.Load("./data/DeepWeight.pfm");
	texture[1]=DeepScatteringWeightHandler.ogl_id;

	TextureHandler ShallowScatteringWeightHandler;
	ShallowScatteringWeightHandler.Load("./data/ShallowWeight.pfm");
	texture[0]=ShallowScatteringWeightHandler.ogl_id;

	TextureHandler MaskHandler;
	MaskHandler.Load("./data/Mask.bmp");
	texture[2]=MaskHandler.ogl_id;

	TextureHandler ShallowScatteringAlbedoHandler;
	ShallowScatteringAlbedoHandler.Load("./data/shallowScatteringAlbedo.pfm");
	texture[3]=ShallowScatteringAlbedoHandler.ogl_id;

	TextureHandler DeepScatteringAlbedoHandler;
	DeepScatteringAlbedoHandler.Load("./data/deepScatteringAlbedo.pfm");
	texture[4]=DeepScatteringAlbedoHandler.ogl_id;

	TextureHandler SpecularAlbedoHandler;
	SpecularAlbedoHandler.Load("./data/specularAlbedo.pfm");
	texture[5]=SpecularAlbedoHandler.ogl_id;

	TextureHandler SpecularNormalHandler;
	SpecularNormalHandler.Load("./data/spec_normal.pfm");
	texture[6]=SpecularNormalHandler.ogl_id;

	TextureHandler SpecularRoughnessHandler;
	SpecularRoughnessHandler.Load("./data/specularRoughness.pfm");
	texture[7]=SpecularRoughnessHandler.ogl_id;


	shallowWeightID=texture[0];
	deepWeightID=texture[1];
	maskID=texture[2];
	shallowAlbedoID=texture[3];
	deepAlbedoID=texture[4];
	specAlbedoID=texture[5];
	chanelS=texture[6];
	specRough=texture[7];

	diffuseWidth=DeepScatteringAlbedoHandler.img_width;
	diffuseHeight=DeepScatteringAlbedoHandler.img_height;

}

void iniShader()
{

	vShadow.m_parameters.clear();
	vShadow.AddParameter("Proj",CG_GL_ARBITRARY_MTX,LightProjectMatrix);
	vShadow.AddParameter("MV",CG_GL_ARBITRARY_MTX,LightMVMatrix);

	fShadow.m_parameters.clear();

	vIrradiance.m_parameters.clear();

	fIrradiance.m_parameters.clear();
	fIrradiance.AddParameter("albedoDeep",CG_GL_TEXTURE_2D,&deepAlbedoID);
	fIrradiance.AddParameter("albedoShallow",CG_GL_TEXTURE_2D,&shallowAlbedoID);
	fIrradiance.AddParameter("albedoS",CG_GL_TEXTURE_2D,&specAlbedoID);
	fIrradiance.AddParameter("chanelS",CG_GL_TEXTURE_2D,&chanelS);
	fIrradiance.AddParameter("roughness",CG_GL_TEXTURE_2D,&specRough);
	fIrradiance.AddParameter("shadowMap",CG_GL_TEXTURE_2D,&(ShadowBuffer.framebuffer.texID[0]));
	fIrradiance.AddParameter("MInverse",CG_GL_ARBITRARY_MTX,MInvMatrix);
	fIrradiance.AddParameter("light",CG_GL_VECTOR_4D,light_position);
	fIrradiance.AddParameter("eye",CG_GL_VECTOR_4D,eye_position);
	fIrradiance.AddParameter("Kd",CG_GL_VECTOR_3D,Kd);
	fIrradiance.AddParameter("LMV",CG_GL_ARBITRARY_MTX,LightMVMatrix);
	fIrradiance.AddParameter("LProj",CG_GL_ARBITRARY_MTX,ProjectiveLightOgl);
	fIrradiance.AddParameter("m",CG_GL_VECTOR_1D,&KmC);
	fIrradiance.AddParameter("fresnel",CG_GL_VECTOR_1D,&KfC);
	fIrradiance.AddParameter("zyf",CG_GL_VECTOR_1D,&debug);
	fIrradiance.AddParameter("singleP",CG_GL_VECTOR_4D,singleParam);

	vWorld2UV.m_parameters.clear();

	fWorld2UV.m_parameters.clear();

	vRender.m_parameters.clear();
	vRender.AddParameter("Proj",CG_GL_ARBITRARY_MTX,ProjectMatrix);
	vRender.AddParameter("MV",CG_GL_ARBITRARY_MTX,MVMatrix);

	fRender.m_parameters.clear();
	fRender.AddParameter("mask",CG_GL_TEXTURE_2D,&(maskID));
	fRender.AddParameter("deepW",CG_GL_TEXTURE_2D,&(deepWeightID));
	fRender.AddParameter("shallowW",CG_GL_TEXTURE_2D,&(shallowWeightID));
	fRender.AddParameter("deepblur0",CG_GL_TEXTURE_2D,&(DeepGaussianBuffer[0].framebuffer.texID[0]));
	fRender.AddParameter("deepblur1",CG_GL_TEXTURE_2D,&(DeepGaussianBuffer[1].framebuffer.texID[0]));
	fRender.AddParameter("deepblur2",CG_GL_TEXTURE_2D,&(DeepGaussianBuffer[2].framebuffer.texID[0]));
	fRender.AddParameter("deepblur3",CG_GL_TEXTURE_2D,&(DeepGaussianBuffer[3].framebuffer.texID[0]));
	fRender.AddParameter("shallowblur0",CG_GL_TEXTURE_2D,&(ShallowGaussianBuffer[0].framebuffer.texID[0]));
	fRender.AddParameter("shallowblur1",CG_GL_TEXTURE_2D,&(ShallowGaussianBuffer[1].framebuffer.texID[0]));
	fRender.AddParameter("shallowblur2",CG_GL_TEXTURE_2D,&(ShallowGaussianBuffer[2].framebuffer.texID[0]));
	fRender.AddParameter("shallowblur3",CG_GL_TEXTURE_2D,&(ShallowGaussianBuffer[3].framebuffer.texID[0]));
	fRender.AddParameter("specTex",CG_GL_TEXTURE_2D,&(IrradianceBuffer.framebuffer.texID[3]));
	fRender.AddParameter("singleTex",CG_GL_TEXTURE_2D,&(IrradianceBuffer.framebuffer.texID[4]));
	fRender.AddParameter("display",CG_GL_VECTOR_1D,&(displayType));


	vGaussianU.m_parameters.clear();

	fGaussianU.m_parameters.clear();
	fGaussianU.AddParameter("irradiance",CG_GL_TEXTURE_2D,&gaussianIrradiance);
	fGaussianU.AddParameter("position",CG_GL_TEXTURE_2D,&gaussianStretch);
	fGaussianU.AddParameter("width",CG_GL_VECTOR_1D,&gaussianWidth);
	fGaussianU.AddParameter("scaleTerm",CG_GL_VECTOR_1D,&scaleTerm);

	vGaussianV.m_parameters.clear();
	vGaussianV.AddParameter("denorm",CG_GL_VECTOR_1D,&denorm);

	fGaussianV.m_parameters.clear();
	fGaussianV.AddParameter("irradiance",CG_GL_TEXTURE_2D,&gaussianIrradiance);
	fGaussianV.AddParameter("position",CG_GL_TEXTURE_2D,&gaussianStretch);
	fGaussianV.AddParameter("width",CG_GL_VECTOR_1D,&gaussianWidth);
	fGaussianV.AddParameter("scaleTerm",CG_GL_VECTOR_1D,&scaleTerm);
}

void loadShader()
{
	vShadow.m_context=context;
	vShadow.Load("vShadow.cg",CG_GL_VERTEX);

	fShadow.m_context=context;
	fShadow.Load("fShadow.cg",CG_GL_FRAGMENT);

	vIrradiance.m_context=context;
	vIrradiance.Load("vIrradiance.cg",CG_GL_VERTEX);

	fIrradiance.m_context=context;
	fIrradiance.Load("fIrradiance.cg",CG_GL_FRAGMENT);

	vRender.m_context=context;
	vRender.Load("vRender.cg",CG_GL_VERTEX);

	fRender.m_context=context;
	fRender.Load("fRender.cg",CG_GL_FRAGMENT);

	vWorld2UV.m_context=context;
	vWorld2UV.Load("vWorld2UV.cg",CG_GL_VERTEX);

	fWorld2UV.m_context=context;
	fWorld2UV.Load("fWorld2UV.cg",CG_GL_FRAGMENT);

	vGaussianU.m_context=context;
	vGaussianU.Load("vGaussianU.cg",CG_GL_VERTEX);

	fGaussianU.m_context=context;
	fGaussianU.Load("fGaussianU.cg",CG_GL_FRAGMENT);

	vGaussianV.m_context=context;
	vGaussianV.Load("vGaussianV.cg",CG_GL_VERTEX);

	fGaussianV.m_context=context;
	fGaussianV.Load("fGaussianV.cg",CG_GL_FRAGMENT);
}

void initCg()
{
	cgSetErrorCallback(cgErrorCallback);
	context=cgCreateContext();
}

void init()
{
	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST);
	//glFrontFace(GL_CW);
	//glCullFace(GL_BACK);
	//glEnable(GL_CULL_FACE);

	Step[0]=1.0/windowWidth;
	Step[1]=1.0/windowHeight;

}
void timer(int p)
{
	glutPostRedisplay();
	glutTimerFunc(20, timer, 0);
}

void updateCgParam()
{
	for (int i=0;i<3;i++)
	{
		Kd[i]=(float)KdC[i]/10.0;
	}
	Kshine=(float)KshineC;
}

void updateMatrix()
{

	float length=0;

	for (int i=0;i<3;i++)
	{
		light_position[i]=0;
		for (int j=0;j<3;j++)
		{
			light_position[i]+=lig_rot[j*4+i];
		}
		length+=light_position[i]*light_position[i];
	}	

	length=sqrt(length);

	for (int i=0;i<3;i++)
	{
		light_position[i]/=length;
		light_position[i]*=light_distance;
	}

	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glViewport(0, 0, (GLsizei) diffuseWidth, (GLsizei) diffuseHeight);



	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(eye_position[0],eye_position[1],eye_position[2],0,0,0 ,0,1,0);
	glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,ProjectMatrix);
	glGetFloatv(GL_MODELVIEW_MATRIX,MVMatrix);	

	float M_lw[16]={1,0,0,0,
		0,1,0,0,
		0,0,1,50,
		0,0,0,1}; 
	float M_ow[16]={1,0,0,0,
		0,1,0,0,
		0,0,1,0,
		0,0,0,1};

	mat4f ligM(lig_rot);
	mat4f objM(obj_rot);

	float eyeO[4]={0,0,35,1};
	float ligO[4]={0,0,35,1};

	vec4f lig(ligO);
	vec4f eye(eyeO);


	mat4f olM=objM.Inverse()*ligM;

	lig=olM.Inverse()*lig;
	eye=objM*eye;

	for (int i=0;i<4;i++)
	{
		for (int j=0;j<4;j++)
		{
			M_ow[i*4+j]=olM[i][j];
			MVMatrix[i*4+j]=objM[i][j];
		}

		light_position[i]=lig[i];
		//eye_position[i]=eye[i];
	}

	MVMatrix[14]=-eye_position[2];


	mat4f Mow(M_ow);
	mat4f Mlw(M_lw);
	mat4f Mol=Mlw.Inverse()*Mow;

	//mat3f

	for (int i=0;i<4;i++)
	{
		for (int j=0;j<4;j++)
		{
			ObjectToLight[i*4+j]=Mol[i][j];
		}
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(30/*45.0f*/,1.3333334/*(GLfloat) diffuseWidth / (GLfloat)diffuseHeight*/ , 30.0f/*0.5f*/, 70.0f/*-1000.0f*/);
	glGetFloatv(GL_PROJECTION_MATRIX, ProjectionLightOgl );

	transposeMatrix(ProjectionLight,ProjectionLightOgl);

	mat4f Mprojectionl(ProjectionLight);

	mat4f Mbias(0.5f, 0.0f, 0.0f, 0.0f,
		0.0f, 0.5f, 0.0f, 0.0f,
		0.0f, 0.0f, 0.5f, 0.0f,
		0.5f, 0.5f, 0.5f, 1.0f);

	Mbias=Mbias.Transpose();

	mat4f Mprojectivel=Mbias*Mprojectionl*Mol;


	for (int i=0;i<4;i++)
	{
		for (int j=0;j<4;j++)
		{
			ProjectiveLight[i*4+j]=Mprojectivel[i][j];
		}
	}


	//glGetFloatv(GL_MODELVIEW,ObjectToLightOgl);


}

void drawModel()
{
	glCallList(displayID[0]);
}

void drawQuad()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glPolygonMode(GL_FRONT,GL_FILL);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(1.0, 0.0); 
	glVertex2f(1.0, 0.0);
	glTexCoord2f(1.0, 1.0); 
	glVertex2f(1.0, 1.0);
	glTexCoord2f(0.0, 1.0); 
	glVertex2f(0.0, 1.0);
	glEnd();
}

void display()
{	

	//printf("%d",specLayer);
	int specB=0, deepsB=0, shallowsB=0, singlesB=0;

	if (specLayer)
	{
		specB=1;
	}

	if (deepsLayer)
	{
		deepsB=2;
	}

	if (shallowsLayer)
	{
		shallowsB=4;
	}

	if (singlesLayer)
	{
		singlesB=8;
	}

	displayType=specB|deepsB|shallowsB|singlesB;


	//printf("%f",displayType);

	updateCgParam();

	updateMatrix();	

	/************************************************************************/
	/*								Stretch Pass                             */
	/************************************************************************/

	if (initial)
	{
		initial=false;

		World2UVBuffer.FBOActivate();

		vWorld2UV.bind();
		fWorld2UV.bind();

		drawModel();

		vWorld2UV.release();
		fWorld2UV.release();

		World2UVBuffer.FBODeactivate();
	}

	updateMatrix();	

	/************************************************************************/
	/*								Shadow Pass                             */
	/************************************************************************/

	transposeMatrix(ProjectionLightOgl,ProjectionLight);
	transposeMatrix(ObjectToLightOgl,ObjectToLight);

	ShadowBuffer.FBOActivate();

	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glViewport(0, 0, windowWidth*2, windowHeight*2);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	//gluPerspective(45.0f,(GLfloat) diffuseWidth / (GLfloat)diffuseHeight , 0.5f, -1000.0f);
	glLoadMatrixf( ProjectionLightOgl );
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glLoadMatrixf(ObjectToLightOgl);
	//gluLookAt(-light_position[0],-light_position[1],-light_position[2],0,0,0 ,0,1,0);
	//glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,LightProjectMatrix);
	glGetFloatv(GL_MODELVIEW_MATRIX,LightMVMatrix);	

	drawModel();

	ShadowBuffer.FBODeactivate();

	/************************************************************************/
	/*						Irradiance Cache Pass                           */
	/************************************************************************/

	IrradianceBuffer.FBOActivate();

	updateMatrix();

	transposeMatrix(ProjectiveLightOgl,ProjectiveLight);

	vIrradiance.bind();
	fIrradiance.bind();

	drawModel();

	vIrradiance.release();
	fIrradiance.release();

	IrradianceBuffer.FBODeactivate();

	/************************************************************************/
	/*						Deep Scattering Pass                            */
	/************************************************************************/

	float gVariance[DEEPBLURSTEP] = {0.036, 0.14, 0.91, 7.0};
	float gWidth[DEEPBLURSTEP];

	gWidth[0] = 0;
	for(int i=1; i<DEEPBLURSTEP; i++)
	{
		float v = gVariance[i] - gVariance[i-1];
		gWidth[i] = sqrtf(v);
	}

	if (deepsLayer)
	{
		for(int i=0; i<DEEPBLURSTEP; i++){

			InterBuffer.FBOActivate();

			updateMatrix();
			gaussianStretch = World2UVBuffer.framebuffer.texID[0];

			if(i==0)
				gaussianIrradiance = IrradianceBuffer.framebuffer.texID[1];
			else
				gaussianIrradiance = DeepGaussianBuffer[i-1].framebuffer.texID[0];

			gaussianWidth = gWidth[i];

			vGaussianU.bind();
			fGaussianU.bind();

			drawQuad();

			vGaussianU.release();
			fGaussianU.release();	

			InterBuffer.FBODeactivate();

			DeepGaussianBuffer[i].FBOActivate();

			updateMatrix();
			gaussianStretch = World2UVBuffer.framebuffer.texID[0];
			gaussianIrradiance = InterBuffer.framebuffer.texID[0];
			gaussianWidth = gWidth[i];

			vGaussianV.bind();
			fGaussianV.bind();

			drawQuad();

			vGaussianV.release();
			fGaussianV.release();	

			DeepGaussianBuffer[i].FBODeactivate();

		}
	}

	/************************************************************************/
	/*					Shallow Scattering Pass                             */
	/************************************************************************/


	if (shallowsLayer)
	{
		for(int i=0; i<SHALLOWBLURSTEP; i++){

			InterBuffer.FBOActivate();

			updateMatrix();
			gaussianStretch = World2UVBuffer.framebuffer.texID[0];

			if(i==0)
				gaussianIrradiance = IrradianceBuffer.framebuffer.texID[2];
			else
				gaussianIrradiance = ShallowGaussianBuffer[i-1].framebuffer.texID[0];

			gaussianWidth = gWidth[i];

			vGaussianU.bind();
			fGaussianU.bind();

			drawQuad();

			vGaussianU.release();
			fGaussianU.release();	

			InterBuffer.FBODeactivate();

			ShallowGaussianBuffer[i].FBOActivate();

			updateMatrix();
			gaussianStretch = World2UVBuffer.framebuffer.texID[0];
			gaussianIrradiance = InterBuffer.framebuffer.texID[0];
			gaussianWidth = gWidth[i];

			vGaussianV.bind();
			fGaussianV.bind();

			drawQuad();

			vGaussianV.release();
			fGaussianV.release();	

			ShallowGaussianBuffer[i].FBODeactivate();

		}
	}

	// Final Combination  

#if 0

	glClearColor(0,0,0,1);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) windowWidth / (GLfloat)windowHeight , 0.5f, -1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, windowWidth, windowHeight);

	glLoadMatrixf(MVMatrix);
	//gluLookAt(eye_position[0],eye_position[1],eye_position[2],0,0,0 ,0,1,0);
	//glMultMatrixf(obj_rot);

	glGetFloatv(GL_PROJECTION_MATRIX,ProjectMatrix);
	//glGetFloatv(GL_MODELVIEW_MATRIX,MVMatrix);	

	vRender.bind();
	fRender.bind();

	//glEnable(GL_TEXTURE_2D);
	//glBindTexture(GL_TEXTURE_2D,World2UVBuffer.framebuffer.texID[0]);

	glCallList(displayID[0]);

	//glDisable(GL_TEXTURE_2D);

	fRender.release();
	vRender.release();

#else

	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, windowWidth, 0.0, windowHeight);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glViewport(0, 0, windowWidth, windowHeight);

	glPolygonMode(GL_FRONT,GL_FILL);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,ShadowBuffer.framebuffer.texID[0]);

	glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0); 
	glVertex2f(0.0, 0.0);
	glTexCoord2f(1.0, 0.0); 
	glVertex2f(windowWidth, 0.0);
	glTexCoord2f(1.0, 1.0); 
	glVertex2f(windowWidth, windowHeight);
	glTexCoord2f(0.0, 1.0); 
	glVertex2f(0.0, windowHeight);
	glEnd();

	glDisable(GL_TEXTURE_2D);

#endif	

	glutSwapBuffers(); 

}

void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0f,(GLfloat) w / (GLfloat)h , 0.5f, -1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void InitModel()
{
	displayID = (int*)malloc(sizeof(int));


	mesh.LoadOBJascii("./data/final_spec_mid.obj");

	displayID[0] = glGenLists(1);
	glNewList(displayID[0], GL_COMPILE);
	glBegin(GL_TRIANGLES);
	for(int j=0; j<mesh.numTris; j++){
		int indexV1 = mesh.tris[j].v1;
		int indexV2 = mesh.tris[j].v2;
		int indexV3 = mesh.tris[j].v3;
		int indexUV1 = mesh.tris[j].uv1;
		int indexUV2 = mesh.tris[j].uv2;
		int indexUV3 = mesh.tris[j].uv3;
		glTexCoord2f(mesh.uvs[indexUV1].u, 1-mesh.uvs[indexUV1].v); 
		glNormal3f(mesh.normal[indexV1].x, mesh.normal[indexV1].y, mesh.normal[indexV1].z);
		//glColor3f(mesh.tangent[indexV1].x, mesh.tangent[indexV1].y, mesh.tangent[indexV1].z);
		glVertex3f(mesh.verts[indexV1].x, mesh.verts[indexV1].y, mesh.verts[indexV1].z);

		glTexCoord2f(mesh.uvs[indexUV2].u, 1-mesh.uvs[indexUV2].v); 
		glNormal3f(mesh.normal[indexV2].x, mesh.normal[indexV2].y, mesh.normal[indexV2].z);
		//glColor3f(mesh.tangent[indexV2].x, mesh.tangent[indexV2].y, mesh.tangent[indexV2].z);
		glVertex3f(mesh.verts[indexV2].x, mesh.verts[indexV2].y, mesh.verts[indexV2].z);

		glTexCoord2f(mesh.uvs[indexUV3].u, 1-mesh.uvs[indexUV3].v); 
		glNormal3f(mesh.normal[indexV3].x, mesh.normal[indexV3].y, mesh.normal[indexV3].z);
		//glColor3f(mesh.tangent[indexV3].x, mesh.tangent[indexV3].y, mesh.tangent[indexV3].z);
		glVertex3f(mesh.verts[indexV3].x, mesh.verts[indexV3].y, mesh.verts[indexV3].z);
	}
	glEnd();
	glEndList();
}

void Keyboard(unsigned char Key, int x, int y)
{
	switch(Key)
	{
	case 'a':
		if (gaussianDisplay>0)
		{
			gaussianDisplay--;
		}	
		break;

	case 's':
		if (gaussianDisplay<DEEPBLURSTEP-1)
		{
			gaussianDisplay++;
		}
		break;

	case 'q':
		//displayType++;
		break;

	case 'w':
		//displayType--;
		break;
	}

	printf("$$$$%d\n",gaussianDisplay);

	glutPostRedisplay();
}

void updateControl(int layer)
{
	switch (layer)
	{
	case SPECLAYER:
		if (specLayer)
		{
			SpecLayerControl->enable();
		}else{
			SpecLayerControl->disable();
		}
		break;

	case SINGLELAYER:
		if (singlesLayer)
		{
			SingleLayerControl->enable();
		}else{
			SingleLayerControl->disable();
		}
		break;

	case DEEPLAYER:
		if (deepsLayer)
		{
			DeepLayerControl->enable();
		}else{
			DeepLayerControl->disable();
		}
		break;

	case SHALLOWLAYER:
		if (shallowsLayer)
		{
			ShallowLayerControl->enable();
		}else{
			ShallowLayerControl->disable();
		}
		break;
	}
	
}

int main(int argc, char *argv[])
{

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(windowWidth, windowHeight);
	GLuint win=glutCreateWindow("Hybrid Normal");
	init();
	initCg();
	InitModel();
	loadTexture();
	initFrameBuffer();
	loadShader();
	iniShader();
	glutTimerFunc(20,timer,0);
	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(Keyboard);

	glui=GLUI_Master.create_glui("Control");

	GLUI_Rollout *Rotation=glui->add_rollout("Rotation");
	GLUI_Rotation *ro=glui->add_rotation_to_panel(Rotation,"World Rotation",(float*)obj_rot);
	ro->reset();
	GLUI_Rotation *rl=glui->add_rotation_to_panel(Rotation,"Light Rotation",(float*)lig_rot);
	rl->reset();

	GLUI_Rollout *Translation=glui->add_rollout("Translation");
	GLUI_Translation *tc=glui->add_translation_to_panel(Translation,"Camera Translation",GLUI_TRANSLATION_Z,&(eye_position[2]));
	tc->set_speed(-0.5);
	tc->set_z(eye_position[2]);

	GLUI_Translation *tl=glui->add_translation_to_panel(Translation,"Light Translation",GLUI_TRANSLATION_Z,&(light_distance));
	tl->set_speed(0.5);
	tl->set_z(light_distance);

	GLUI_Rollout *LayerControl=glui->add_rollout("Layer");
	GLUI_Checkbox *specl=glui->add_checkbox_to_panel(LayerControl,"Specular Layer",&specLayer,SPECLAYER,updateControl);
	GLUI_Checkbox *singlesl=glui->add_checkbox_to_panel(LayerControl,"Single Layer",&singlesLayer,SINGLELAYER,updateControl);
	GLUI_Checkbox *deepsl=glui->add_checkbox_to_panel(LayerControl,"Deep Scattering Layer",&deepsLayer,DEEPLAYER,updateControl);
	GLUI_Checkbox *shallowsl=glui->add_checkbox_to_panel(LayerControl,"Shallow Scattering Layer",&shallowsLayer,SHALLOWLAYER,updateControl);
	GLUI_Scrollbar *scale=new GLUI_Scrollbar(LayerControl,"Scale",GLUI_SCROLL_HORIZONTAL,&(scaleTerm));
	scale->set_float_limits(0,10);

	SingleLayerControl=glui->add_rollout("Single Layer");
	GLUI_StaticText *meancos_name=glui->add_statictext_to_panel(SingleLayerControl,"Mean Cosine");
	GLUI_Scrollbar *meancos=new GLUI_Scrollbar(SingleLayerControl, "MeanCos",GLUI_SCROLL_HORIZONTAL,&(singleParam[0]));
	meancos->set_float_limits(-1,1);
	GLUI_StaticText *transmit_name=glui->add_statictext_to_panel(SingleLayerControl,"Transmitance");
	GLUI_Scrollbar *transmit = new GLUI_Scrollbar( SingleLayerControl, "Transmit",GLUI_SCROLL_HORIZONTAL,&(singleParam[1]));
	transmit->set_float_limits(0,1); 
	SingleLayerControl->disable();
	
	SpecLayerControl=glui->add_rollout("Specular Layer");
	SpecLayerControl->disable();

	DeepLayerControl=glui->add_rollout("Deep Scattering Layer");
	DeepLayerControl->disable();

	ShallowLayerControl=glui->add_rollout("Shallow Scattering Layer");
	ShallowLayerControl->disable();	

	glui->set_main_gfx_window(win);


	glutMainLoop();
	return 0;
}